package cn.shop.merchant.service;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.shop.merchant.req.WithdrawQueryReq;
import cn.shop.transcation.alipay.entity.AlipayAccount;
import cn.shop.transcation.backSetting.entity.BackSetting;
import cn.shop.transcation.backSetting.mapper.BackSettingMapper;
import cn.shop.transcation.bankcard.entity.BankCard;
import cn.shop.transcation.detail.entity.FundDetail;
import cn.shop.transcation.detail.mapper.FundDetailMapper;
import cn.shop.transcation.merchantUser.mapper.entity.MerchantUser;
import cn.shop.transcation.withdraw.entity.Withdraw;
import cn.shop.transcation.withdraw.mapper.WithdrawMapper;
import cn.shop.utils.ApiResult;
import cn.shop.utils.PageUtil;
import cn.shop.utils.Putif;
import cn.shop.utils.enums.ProcessState;
import cn.shop.utils.enums.WithdrawAccountType;
import cn.shop.utils.enums.WithdrawSolution;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.shop.utils.constant.SystemSettingConstant.U_ALI_WITHDRAW_SHARE;
import static cn.shop.utils.constant.SystemSettingConstant.U_ALI_WITHDRAW_SUB;
import static cn.shop.utils.constant.SystemSettingConstant.U_BANK_WITHDRAW_SHARE;
import static cn.shop.utils.constant.SystemSettingConstant.U_BANK_WITHDRAW_SUB;
import static cn.shop.utils.constant.SystemSettingConstant.WITHDRAW_MAX;
import static cn.shop.utils.constant.SystemSettingConstant.WITHDRAW_MIN;

/**
 * @author : 李一涵
 * @date : Created in 2022-2-25 16:48
 * @description :
 */
@Service
public class WithdrawService extends BaseServiceImpl<WithdrawMapper, Withdraw> {

	private final static Logger LOG = LoggerFactory.getLogger(WithdrawService.class);

	@Resource
	private MerchantUserService userService;

	@Resource
	private BankCardService bankCardService;

	@Resource
	private AlipayService alipayService;

	@Resource
	private BackSettingMapper settingMapper;

	@Resource
	private FundDetailMapper fundDetailMapper;


	@Transactional(rollbackFor = Exception.class)
	public ApiResult<Map<String, Object>> withdraw(long userId, BigDecimal amount, long id, String type, String password) {
		MerchantUser user = userService.getById(userId);
		if (user == null) {
			return ApiResult.fail("用户不存在");
		}
		if (user.getBalance().compareTo(amount) < 0) {
			return ApiResult.fail("可提现金额不足");
		}
		if (!DigestUtil.bcryptCheck(password, user.getTransactionPassword())) {
			return ApiResult.fail("交易密码不正确");
		}
		Withdraw withdraw = new Withdraw();
		withdraw.setUserId(userId);
		withdraw.setAmount(amount);
		withdraw.setBalance(user.getBalance().subtract(amount));
		withdraw.setState(ProcessState.UNTREATED);
		withdraw.setType(1);
		BigDecimal charges;
		//rate 百分比提成， single 单笔扣款
		BigDecimal rate = BigDecimal.ZERO, single = BigDecimal.ZERO;
		if (StrUtil.equals(type, "1")) {
			BankCard card = bankCardService.getById(id);
			if (card == null) {
				return ApiResult.fail("银行卡信息不存在");
			}
			//百分比提成计算share1
			String v = getSettingValue(U_BANK_WITHDRAW_SHARE);
			if (NumberUtil.isNumber(v)) {
				charges = new BigDecimal(v).divide(new BigDecimal(100), 4, RoundingMode.CEILING);
				if (charges.compareTo(BigDecimal.ZERO) > 0) {
					rate = amount.multiply(charges);
				}
			}
			//计算单笔扣款
			String v2 = getSettingValue(U_BANK_WITHDRAW_SUB);
			if (NumberUtil.isNumber(v)) {
				charges = new BigDecimal(v2);
				if (charges.compareTo(BigDecimal.ZERO) > 0) {
					single = charges;
				}
			}
			withdraw.setActualAmount(amount.subtract(rate).subtract(single));
			withdraw.setCharges(rate.add(single));
			withdraw.setAccount(card.getCardNo());
			withdraw.setAccountType(WithdrawAccountType.BANK_PAYMENT);
			withdraw.setBankName(card.getBankName());
			withdraw.setBankAccountName(card.getName());
		}
		else {
			AlipayAccount alipay = alipayService.getById(id);
			if (alipay == null) {
				return ApiResult.fail("支付宝信息不存在");
			}
			//百分比提成计算share1
			String v = getSettingValue(U_ALI_WITHDRAW_SHARE);
			if (NumberUtil.isNumber(v)) {
				charges = new BigDecimal(v).divide(new BigDecimal(100), 4, RoundingMode.CEILING);
				if (charges.compareTo(BigDecimal.ZERO) > 0) {
					rate = amount.multiply(charges);
				}
			}
			//计算单笔扣款
			String v2 = getSettingValue(U_ALI_WITHDRAW_SUB);
			if (NumberUtil.isNumber(v)) {
				charges = new BigDecimal(v2);
				if (charges.compareTo(BigDecimal.ZERO) > 0) {
					single = charges;
				}
			}
			withdraw.setActualAmount(amount.subtract(rate).subtract(single));
			withdraw.setCharges(rate.add(single));
			withdraw.setAccount(alipay.getAccount());
			withdraw.setAccountType(WithdrawAccountType.ALIPAY_PAYMENT);
			withdraw.setBankAccountName(alipay.getName());
		}
		withdraw.setChargeRate(rate);
		withdraw.setChargeSingle(single);
		withdraw.setIdCard(user.getIdentityCard());
		withdraw.setPhone(user.getPhone());
		boolean success = save(withdraw);
		if (!success) {
			ApiResult.fail("提现失败");
		}
		MerchantUser update = new MerchantUser();
		update.setBalance(user.getBalance().subtract(amount));
		success = userService.update(update, Wrappers.<MerchantUser>lambdaQuery().eq(MerchantUser::getId, userId));
		if (!success) {
			LOG.warn("修改用户可提现金额失败, 用户号：{}， 时间：{}", userId, LocalDateTime.now());
			throw new RuntimeException("提现失败");
		}
		FundDetail detail = new FundDetail();
		detail.setType(3);
		detail.setOrderId(withdraw.getId());
		detail.setPlayerId(userId);
		detail.setPlayerAccount(user.getAccount());
		detail.setPlatformShare(withdraw.getCharges());
		detail.setBalance(update.getBalance());
		detail.setAmount(amount);
		detail.setGoods("商户提现");
		detail.setDealTime(LocalDateTime.now());
		fundDetailMapper.insert(detail);
		return ApiResult.success("提现成功");
	}

	public Map<String, Object> listPage(long userId, WithdrawQueryReq req) {
		Page<Withdraw> page = Page.of(req.getCurrent(), req.getSize());
		LambdaQueryWrapper<Withdraw> query = Wrappers.<Withdraw>lambdaQuery()
				.eq(Withdraw::getUserId, userId)
				.eq(req.getState() != null, Withdraw::getState, req.getState())
				.apply(notNull.test(req.getStartTime()), req.gtTime("create_time"), req.getStartTime())
				.apply(notNull.test(req.getEndTime()), req.ltTime("create_time"), req.getEndTime())
				.orderByDesc(Withdraw::getId);
		page = page(page, query);
		return PageUtil.formatPage(page, this::format);
	}

	public Map<String, String> withdrawRange() {
		List<BackSetting> list = settingMapper.selectList(Wrappers.<BackSetting>lambdaQuery()
				.in(BackSetting::getKey, Arrays.asList(WITHDRAW_MIN, WITHDRAW_MAX)));
		return list.stream().collect(Collectors.toMap(BackSetting::getKey, BackSetting::getValue));
	}

	private String getSettingValue(String key) {
		BackSetting setting = settingMapper.selectOne(Wrappers.<BackSetting>lambdaQuery().eq(BackSetting::getKey, key));
		return setting.getValue();
	}

	private Map<String, Object> format(Withdraw withdraw) {
		return Putif.start()
				.anyway("time", withdraw.getCreateTime())
				.anyway("amount", withdraw.getAmount())
				.anyway("balance", withdraw.getBalance())
				.anyway("account", DesensitizedUtil.idCardNum(withdraw.getAccount(), 2, 2))
				.anyway("channel", withdraw.getAccountType().getDescription())
				.anyway("state", withdraw.getState() == ProcessState.ABNORMAL && withdraw.getSolution() == WithdrawSolution.SEND_BACK
						? "已退回"
						: withdraw.getState().getType())
				.get();
	}

}
